home *** CD-ROM | disk | FTP | other *** search
/ Aminet 20 / Aminet 20 (1997)(GTI - Schatztruhe)[!][Aug 1997].iso / Aminet / comm / www / HTP.lha / HTP / source / suballoc.c < prev    next >
C/C++ Source or Header  |  1997-06-21  |  17KB  |  752 lines

  1. /*
  2. //
  3. // suballoc.c
  4. //
  5. // Memory suballocation
  6. //
  7. // Copyright (c) 1995-96 Jim Nelson.  Permission to distribute
  8. // granted by the author.  No warranties are made on the fitness of this
  9. // source code.
  10. // Amiga version - 1997 - Geert Bevin
  11. //
  12. */
  13.  
  14. #include "htp.h"
  15.  
  16. /*
  17. // performance counters
  18. */
  19. #if DEBUG
  20. uint freePoolHits = 0;
  21. uint totalAllocations = 0;
  22. #endif
  23.  
  24. /*
  25. // pattern used to clear memory on allocation and free
  26. */
  27.  
  28. #define SUBALLOC_ALLOC_BYTE                 (0xA5)
  29. #define SUBALLOC_FREE_BYTE                  (0x5A)
  30.  
  31. /*
  32. // each memory allocation has a small header, which is used by
  33. // this module alone
  34. */
  35.  
  36. #define SUBALLOC_MAX_HEADER_FILE_SIZE               (16)
  37.  
  38. typedef struct tagSUBALLOC_HEADER
  39. {
  40.     struct tagSUBALLOC_HEADER *next;
  41.     struct tagSUBALLOC_HEADER *prev;
  42.     char            file[SUBALLOC_MAX_HEADER_FILE_SIZE];
  43.     uint            line;
  44.     uint            allocSize;
  45.     uint            userSize;
  46.     DWORD           signature;
  47. } SUBALLOC_HEADER;
  48.  
  49. #define SUBALLOC_SIGNATURE                  (0xFEA55AEF)
  50. #define SUBALLOC_END_SIGNATURE              (0xA5EFFE5A)
  51.  
  52. /*
  53. // the memory pool is kept on a doubly-linked list
  54. */
  55.  
  56. typedef struct tagSUBALLOC_POOL
  57. {
  58.     SUBALLOC_HEADER *head;
  59.     SUBALLOC_HEADER *tail;
  60.     uint            totalMemorySize;
  61. } SUBALLOC_POOL;
  62.  
  63. SUBALLOC_POOL freePool;
  64. SUBALLOC_POOL reservedPool;
  65.  
  66. /*
  67. // memory pool functions
  68. */
  69.  
  70. void InitializePool(SUBALLOC_POOL *pool)
  71. {
  72.     assert(pool != NULL);
  73.  
  74.     pool->head = NULL;
  75.     pool->tail = NULL;
  76.     pool->totalMemorySize = 0;
  77. }
  78.  
  79. SUBALLOC_HEADER *PointerToHeader(void *ptr)
  80. {
  81.     assert(ptr != NULL);
  82.     return (SUBALLOC_HEADER *) (((BYTE *) ptr) - sizeof(SUBALLOC_HEADER));
  83. }
  84.  
  85. void *GetUserBuffer(SUBALLOC_HEADER *header)
  86. {
  87.     /* cant assert good header, this function might be used during its */
  88.     /* construction */
  89.     assert(header != NULL);
  90.     return ((BYTE *) header) + sizeof(SUBALLOC_HEADER);
  91. }
  92.  
  93. BOOL IsHeaderOkay(SUBALLOC_HEADER *header)
  94. {
  95.     if(header == NULL)
  96.     {
  97.         DebugMsg("IsHeaderOkay: NULL header\n");
  98.         return FALSE;
  99.     }
  100.  
  101.     /* check head signature */
  102.     if(header->signature != SUBALLOC_SIGNATURE)
  103.     {
  104.         DebugMsg("IsHeaderOkay: bad start signature, file %s line %u\n",
  105.             header->file, header->line);
  106.         return FALSE;
  107.     }
  108.  
  109.     return TRUE;
  110. }
  111.  
  112. void SetEndSignature(SUBALLOC_HEADER *header)
  113. {
  114.     BYTE *startSignature;
  115.     static DWORD endSignature = SUBALLOC_END_SIGNATURE;
  116.  
  117.     assert(header != NULL);
  118.  
  119.     /* find the first byte of the area beyond the user-allocated buffer */
  120.     startSignature = (BYTE *) header + sizeof(SUBALLOC_HEADER)
  121.         + header->userSize;
  122.  
  123.     /* since some machines don't like misaligned accesses, copy the signature */
  124.     /* in byte by byte */
  125.     memcpy(startSignature, &endSignature, sizeof(DWORD));
  126. }
  127.  
  128. BOOL IsEndSignatureOkay(SUBALLOC_HEADER *header)
  129. {
  130.     BYTE *startSignature;
  131.     static DWORD endSignature = SUBALLOC_END_SIGNATURE;
  132.  
  133.     assert(header != NULL);
  134.  
  135.     /* find the first byte beyond the user-allocated buffer */
  136.     startSignature = (BYTE *) header + sizeof(SUBALLOC_HEADER)
  137.         + header->userSize;
  138.  
  139.     /* since some machines don't like misaligned accessed, compare the */
  140.     /* signature byte by byte */
  141.     return (memcmp(startSignature, &endSignature, sizeof(DWORD)) == 0)
  142.         ? TRUE : FALSE;
  143. }
  144.  
  145. SUBALLOC_HEADER *CreatePoolElement(uint size)
  146. {
  147.     SUBALLOC_HEADER *header;
  148.     uint allocSize;
  149.  
  150. #if SUBALLOC_MINALLOCSIZE
  151.     allocSize = (size < SUBALLOC_MINALLOCSIZE) ? SUBALLOC_MINALLOCSIZE : size;
  152. #else
  153.     allocSize = size;
  154. #endif
  155.  
  156.     /* allocate header, end signature, and user buffer */
  157.     if((header = malloc(allocSize + sizeof(SUBALLOC_HEADER) + sizeof(DWORD))) == NULL)
  158.     {
  159.         return NULL;
  160.     }
  161.  
  162. #if DEBUG
  163.     header->next = (void *) 0x12345678;
  164.     header->prev = (void *) 0x12345678;
  165. #endif
  166.  
  167.     /* set up as much of the header as possible */
  168.     header->allocSize = allocSize;
  169.     header->userSize = size;
  170.     header->signature = SUBALLOC_SIGNATURE;
  171.  
  172. #if SUBALLOC_CLEARMEM
  173.     memset(GetUserBuffer(header), SUBALLOC_ALLOC_BYTE, allocSize);
  174. #endif
  175.  
  176.     /* set the end signature */
  177.     SetEndSignature(header);
  178.  
  179.     assert(IsHeaderOkay(header) == TRUE);
  180.     assert(IsEndSignatureOkay(header) == TRUE);
  181.  
  182.     return header;
  183. }
  184.  
  185. void FreePoolElement(SUBALLOC_HEADER *header)
  186. {
  187.     assert(IsHeaderOkay(header) == TRUE);
  188.  
  189. #if SUBALLOC_CLEARMEM
  190.     memset(GetUserBuffer(header), SUBALLOC_FREE_BYTE, header->allocSize);
  191. #endif
  192.  
  193.     free(header);
  194. }
  195.  
  196. SUBALLOC_HEADER *ResizePoolElement(SUBALLOC_HEADER *header, uint newSize)
  197. {
  198.     uint allocSize;
  199.     SUBALLOC_HEADER *newHeader;
  200.  
  201.     assert(IsHeaderOkay(header) == TRUE);
  202.     assert(newSize != 0);
  203.  
  204. #if SUBALLOC_MINALLOCSIZE
  205.     allocSize = (newSize < SUBALLOC_MINALLOCSIZE) ? SUBALLOC_MINALLOCSIZE
  206.         : newSize;
  207. #else
  208.     allocSize = newSize;
  209. #endif
  210.  
  211.     /* it COULD already be this size */
  212.     if(header->allocSize >= allocSize)
  213.     {
  214.         header->userSize = newSize;
  215.         SetEndSignature(header);
  216.  
  217.         assert(IsHeaderOkay(header) == TRUE);
  218.         assert(IsEndSignatureOkay(header) == TRUE);
  219.  
  220.         return header;
  221.     }
  222.  
  223.     newHeader = realloc(header, newSize + sizeof(SUBALLOC_HEADER) + sizeof(DWORD));
  224.     if(newHeader == NULL)
  225.     {
  226.         /* couldnt resize block */
  227.         return NULL;
  228.     }
  229.  
  230. #if DEBUG
  231.     newHeader->prev = (void *) 0x12345678;
  232.     newHeader->next = (void *) 0x12345678;
  233. #endif
  234.  
  235.     /* fill in the new header */
  236.     newHeader->userSize = newSize;
  237.     newHeader->allocSize = allocSize;
  238.     newHeader->signature = SUBALLOC_SIGNATURE;
  239.  
  240.     /* set the end signature */
  241.     SetEndSignature(header);
  242.  
  243.     assert(IsHeaderOkay(newHeader) == TRUE);
  244.     assert(IsEndSignatureOkay(newHeader) == TRUE);
  245.  
  246.     return newHeader;
  247. }
  248.  
  249. void AddPoolElement(SUBALLOC_POOL *pool, SUBALLOC_HEADER *header)
  250. {
  251.     assert(pool != NULL);
  252.     assert(IsHeaderOkay(header) == TRUE);
  253.  
  254.     if(pool->head != NULL)
  255.     {
  256.         header->prev = pool->tail;
  257.         pool->tail->next = header;
  258.     }
  259.     else
  260.     {
  261.         pool->head = header;
  262.         header->prev = NULL;
  263.     }
  264.  
  265.     header->next = NULL;
  266.     pool->tail = header;
  267.  
  268.     pool->totalMemorySize += header->allocSize;
  269. }
  270.  
  271. SUBALLOC_HEADER *RemoveFirstElement(SUBALLOC_POOL *pool)
  272. {
  273.     SUBALLOC_HEADER *header;
  274.  
  275.     assert(pool != NULL);
  276.  
  277.     if(pool->head == NULL)
  278.     {
  279.         return NULL;
  280.     }
  281.  
  282.     header = pool->head;
  283.     if((pool->head = header->next) != NULL)
  284.     {
  285.         pool->head->prev = NULL;
  286.     }
  287.  
  288.     assert(pool->totalMemorySize >= header->allocSize);
  289.     pool->totalMemorySize -= header->allocSize;
  290.  
  291.     assert(IsHeaderOkay(header) == TRUE);
  292.  
  293.     return header;
  294. }
  295.  
  296. void RemoveElement(SUBALLOC_POOL *pool, SUBALLOC_HEADER *header)
  297. {
  298.     assert(pool != NULL);
  299.     assert(IsHeaderOkay(header) == TRUE);
  300.  
  301.     if(pool->head == header)
  302.     {
  303.         pool->head = header->next;
  304.         if(pool->head != NULL)
  305.         {
  306.             pool->head->prev = NULL;
  307.         }
  308.     }
  309.     else if(pool->tail == header)
  310.     {
  311.         pool->tail = header->prev;
  312.         if(pool->tail != NULL)
  313.         {
  314.             pool->tail->next = NULL;
  315.         }
  316.     }
  317.     else
  318.     {
  319.         header->prev->next = header->next;
  320.         header->next->prev = header->prev;
  321.     }
  322.  
  323.     assert(pool->totalMemorySize >= header->allocSize);
  324.     pool->totalMemorySize -= header->allocSize;
  325. }
  326.  
  327. SUBALLOC_HEADER *RemovePoolElementBySize(SUBALLOC_POOL *pool, uint size)
  328. {
  329.     SUBALLOC_HEADER *curr;
  330.  
  331. #if !SUBALLOC_FIRSTFIT
  332.     SUBALLOC_HEADER *bestfit;
  333.     uint bestfitDiff;
  334.     uint currDiff;
  335. #endif
  336.  
  337.     assert(pool != NULL);
  338.     assert(size != 0);
  339.  
  340. #if !SUBALLOC_FIRSTFIT
  341.     bestfit = NULL;
  342.     bestfitDiff = UINT_MAX;
  343. #endif
  344.  
  345.     curr = pool->head;
  346.     while(curr != NULL)
  347.     {
  348.         assert(IsHeaderOkay(curr) == TRUE);
  349.  
  350.         if(curr->allocSize < size)
  351.         {
  352.             /* too small */
  353.             curr = curr->next;
  354.             continue;
  355.         }
  356.  
  357. #if SUBALLOC_FIRSTFIT
  358.         /* found one, unlink from the list */
  359.         RemoveElement(pool, curr);
  360.  
  361. #if SUBALLOC_DEBLOG
  362.         DebugMsg("suballoc: first fit found block of %u bytes for alloc of %u bytes\n",
  363.             curr->allocSize, size);
  364. #endif
  365.  
  366.         return curr;
  367. #else
  368.  
  369. #if SUBALLOC_MINALLOCSIZE
  370.         /* if the block is the minimum allocation size, then it is the */
  371.         /* best fit, by definition */
  372.         if(curr->allocSize == SUBALLOC_MINALLOCSIZE)
  373.         {
  374.             bestfit = curr;
  375.             break;
  376.         }
  377. #endif
  378.  
  379.         currDiff = curr->allocSize - size;
  380.         if(currDiff == 0)
  381.         {
  382.             /* this is as good as it gets */
  383.             bestfit = curr;
  384.             break;
  385.         }
  386.  
  387.         if(currDiff < bestfitDiff)
  388.         {
  389.             bestfitDiff = currDiff;
  390.             bestfit = curr;
  391.         }
  392.  
  393.         curr = curr->next;
  394. #endif
  395.     }
  396.  
  397. #if !SUBALLOC_FIRSTFIT
  398.     if(bestfit != NULL)
  399.     {
  400.         RemoveElement(pool, bestfit);
  401.  
  402. #if SUBALLOC_DEBLOG
  403.         DebugMsg("suballoc: best fit found block of %u bytes for alloc of %u bytes\n",
  404.             bestfit->allocSize, size);
  405. #endif
  406.  
  407.         return bestfit;
  408.     }
  409. #endif
  410.  
  411.     /* nothing was found */
  412.     return NULL;
  413. }
  414.  
  415. BOOL RemovePoolElementByAddr(SUBALLOC_POOL *pool, SUBALLOC_HEADER *header)
  416. {
  417.     SUBALLOC_HEADER *curr;
  418.  
  419.     assert(pool != NULL);
  420.     assert(IsHeaderOkay(header) == TRUE);
  421.  
  422.     curr = pool->head;
  423.     while(curr != NULL)
  424.     {
  425.         assert(IsHeaderOkay(curr) == TRUE);
  426.  
  427.         if(curr == header)
  428.         {
  429.             RemoveElement(pool, curr);
  430.             return TRUE;
  431.         }
  432.  
  433.         curr = curr->next;
  434.     }
  435.  
  436.     return FALSE;
  437. }
  438.  
  439. void RemoveLargestPoolElement(SUBALLOC_POOL *pool)
  440. {
  441.     SUBALLOC_HEADER *curr;
  442.     SUBALLOC_HEADER *largest;
  443.  
  444.     assert(pool != NULL);
  445.  
  446.     largest = NULL;
  447.  
  448.     /* walk the list, looking for the largest allocated block */
  449.     for(curr = pool->head; curr != NULL; curr = curr->next)
  450.     {
  451.         assert(IsHeaderOkay(curr) == TRUE);
  452.  
  453.         if(largest == NULL)
  454.         {
  455.             largest = curr;
  456.             continue;
  457.         }
  458.  
  459.         if(curr->allocSize > largest->allocSize)
  460.         {
  461.             largest = curr;
  462.             continue;
  463.         }
  464.     }
  465.  
  466.     /* if one was found, remove it */
  467.     if(largest != NULL)
  468.     {
  469. #if SUBALLOC_DEBLOG
  470.         DebugMsg("removing largest buffer of %u bytes from pool of %u bytes\n",
  471.             largest->allocSize, pool->totalMemorySize);
  472. #endif
  473.  
  474.         if(largest->prev != NULL)
  475.         {
  476.             largest->prev->next = largest->next;
  477.         }
  478.  
  479.         if(largest->next != NULL)
  480.         {
  481.             largest->next->prev = largest->prev;
  482.         }
  483.  
  484.         /* removed, so destroy it and account for it in the pool */
  485.         assert(pool->totalMemorySize >= largest->allocSize);
  486.         pool->totalMemorySize -= largest->allocSize;
  487.         FreePoolElement(largest);
  488.     }
  489. }
  490.  
  491. /*
  492. // public functions
  493. */
  494.  
  495. void InitializeMemory(void)
  496. {
  497.     InitializePool(&freePool);
  498.     InitializePool(&reservedPool);
  499. }
  500.  
  501. void TerminateMemory(void)
  502. {
  503.     SUBALLOC_HEADER *header;
  504.  
  505.     if(reservedPool.head != NULL)
  506.     {
  507. #if SUBALLOC_DEBLOG
  508.         DebugMsg("UNFREED MEMORY: %u bytes held in reserved pool\n",
  509.             reservedPool.totalMemorySize);
  510. #endif
  511.  
  512. #if SUBALLOC_WARNING
  513.         printf("suballoc: %u bytes unfreed\n", reservedPool.totalMemorySize);
  514. #endif
  515.     }
  516.  
  517. #if SUBALLOC_DEBLOG
  518.     DebugMsg("suballoc: %u bytes held in free pool\n", freePool.totalMemorySize);
  519. #endif
  520.  
  521.     while((header = RemoveFirstElement(&reservedPool)) != NULL)
  522.     {
  523.         assert(IsHeaderOkay(header) == TRUE);
  524.         assert(IsEndSignatureOkay(header) == TRUE);
  525.  
  526. #if SUBALLOC_DEBLOG
  527.         DebugMsg("Removing reserved alloc for %u bytes from %s line %u\n", header->userSize,
  528.             header->file, header->line);
  529. #endif
  530.  
  531.         FreePoolElement(header);
  532.     }
  533.  
  534.     while((header = RemoveFirstElement(&freePool)) != NULL)
  535.     {
  536.         assert(IsHeaderOkay(header) == TRUE);
  537.         /* dont check end signature, it is not valid in free pool */
  538.  
  539. #if SUBALLOC_DEBLOG
  540.         DebugMsg("Removing free alloc for %u bytes from %s line %u\n",
  541.             header->userSize, header->file, header->line);
  542. #endif
  543.         FreePoolElement(header);
  544.     }
  545. }
  546.  
  547. void *_AllocMemory(uint size, const char *file, uint line)
  548. {
  549.     SUBALLOC_HEADER *header;
  550.  
  551. #if SUBALLOC_DEBLOG
  552.     DebugMsg("Allocating %u bytes in file %s line %u\n", size, file, line);
  553. #endif
  554.  
  555. #if DEBUG
  556.     totalAllocations++;
  557. #endif
  558.  
  559.     if(size == 0)
  560.     {
  561. #if SUBALLOC_DEBLOG
  562.         DebugMsg("Allocation for 0 bytes in file %s line %u\n", file, line);
  563. #endif
  564.         return NULL;
  565.     }
  566.  
  567.     /* if buffer of sufficient size already in pool, use that one */
  568.     if((header = RemovePoolElementBySize(&freePool, size)) == NULL)
  569.     {
  570.         /* need to create a new pool item */
  571.         if((header = CreatePoolElement(size)) == NULL)
  572.         {
  573.             /* out of memory! */
  574. #if SUBALLOC_DEBLOG
  575.             DebugMsg("System heap out of memory! file %s line %u\n", file, line);
  576. #endif
  577.             return NULL;
  578.         }
  579.     }
  580.     else
  581.     {
  582. #if DEBUG
  583.         freePoolHits++;
  584. #endif
  585.     }
  586.  
  587.     assert(IsHeaderOkay(header) == TRUE);
  588.  
  589.     /* replace the headers file and line with this new information */
  590.     if(file != NULL)
  591.     {
  592.         StringCopy(header->file, file, SUBALLOC_MAX_HEADER_FILE_SIZE);
  593.     }
  594.     else
  595.     {
  596.         header->file[0] = NUL;
  597.     }
  598.     header->line = line;
  599.  
  600.     header->userSize = size;
  601.  
  602.     /* set the end signature */
  603.     SetEndSignature(header);
  604.  
  605.     /* add the new suballoc to the reserved pool */
  606.     AddPoolElement(&reservedPool, header);
  607.  
  608.     assert(IsHeaderOkay(header) == TRUE);
  609.     assert(IsEndSignatureOkay(header) == TRUE);
  610.  
  611.     return GetUserBuffer(header);
  612. }
  613.  
  614. void _FreeMemory(void *ptr, const char *file, uint line)
  615. {
  616.     SUBALLOC_HEADER *header;
  617.  
  618. #if !SUBALLOC_DEBLOG
  619.     UNREF_PARAM(file);
  620.     UNREF_PARAM(line);
  621. #endif
  622.  
  623.     if(ptr == NULL)
  624.     {
  625. #if SUBALLOC_DEBLOG
  626.         DebugMsg("Tried to free NULL pointer in file %s line %u\n", file, line);
  627. #endif
  628.         return;
  629.     }
  630.  
  631.     header = (SUBALLOC_HEADER *) (((BYTE *) ptr) - sizeof(SUBALLOC_HEADER));
  632.     assert(IsHeaderOkay(header) == TRUE);
  633.     assert(IsEndSignatureOkay(header) == TRUE);
  634.  
  635. #if SUBALLOC_DEBLOG
  636.     DebugMsg("Freeing %u bytes (%u alloced) in file %s line %u\n",
  637.         header->userSize, header->allocSize, file, line);
  638. #endif
  639.  
  640.     if(RemovePoolElementByAddr(&reservedPool, header) == FALSE)
  641.     {
  642.         /* doh! */
  643.         HtpMsg(MSG_ERROR, NULL, "Fatal error: block of memory freed not in reserved pool, exiting ...\n");
  644.         exit(1);
  645.     }
  646.  
  647. #if SUBALLOC_CLEARMEM
  648.     memset(GetUserBuffer(header), SUBALLOC_FREE_BYTE, header->allocSize);
  649. #endif
  650.  
  651.     /* move it back into the free pool */
  652.     AddPoolElement(&freePool, header);
  653.  
  654. #if SUBALLOC_MAXFREEPOOLSIZE
  655.     /* check to see that the free pool size hasnt grown too big */
  656.     while(freePool.totalMemorySize > SUBALLOC_MAXFREEPOOLSIZE)
  657.     {
  658.         RemoveLargestPoolElement(&freePool);
  659.     }
  660. #endif
  661. }
  662.  
  663. void *_ResizeMemory(void *ptr, uint newSize, const char *file, uint line)
  664. {
  665.     SUBALLOC_HEADER *header;
  666.     SUBALLOC_HEADER *newHeader;
  667.  
  668. #if SUBALLOC_DEBLOG
  669.     DebugMsg("Reallocing to new size of %u bytes in file %s line %u\n",
  670.         newSize, file, line);
  671. #endif
  672.  
  673.     if((newSize == 0) && (ptr != NULL))
  674.     {
  675.         /* treat as a free */
  676.         FreeMemory(ptr);
  677.         return NULL;
  678.     }
  679.  
  680.     if((ptr == NULL) && (newSize != 0))
  681.     {
  682.         /* treat as an alloc */
  683.         return AllocMemory(newSize);
  684.     }
  685.  
  686.     if((ptr == NULL) && (newSize == 0))
  687.     {
  688.         /* treat as a dumbo programmer */
  689.         return NULL;
  690.     }
  691.  
  692.     header = PointerToHeader(ptr);
  693.     assert(IsHeaderOkay(header) == TRUE);
  694.     assert(IsEndSignatureOkay(header) == TRUE);
  695.  
  696.     if(RemovePoolElementByAddr(&reservedPool, header) == FALSE)
  697.     {
  698.         /* oof */
  699.         HtpMsg(MSG_ERROR, NULL, "Fatal error: block of memory freed not in reserved pool, exiting ...\n");
  700.         exit(1);
  701.     }
  702.  
  703.     /* resize memory buffer */
  704.     newHeader = ResizePoolElement(header, newSize);
  705.     if(newHeader == NULL)
  706.     {
  707.         /* failed to resize */
  708.         AddPoolElement(&reservedPool, header);
  709.         return NULL;
  710.     }
  711.  
  712.     /* succeeded, fill in rest of header */
  713.     if(file != NULL)
  714.     {
  715.         StringCopy(newHeader->file, file, SUBALLOC_MAX_HEADER_FILE_SIZE);
  716.     }
  717.     else
  718.     {
  719.         newHeader->file[0] = NUL;
  720.     }
  721.     newHeader->line = line;
  722.  
  723.     /* add to reserve pool and return to user */
  724.     AddPoolElement(&reservedPool, newHeader);
  725.  
  726.     assert(IsHeaderOkay(newHeader) == TRUE);
  727.     assert(IsEndSignatureOkay(newHeader) == TRUE);
  728.  
  729.     return GetUserBuffer(newHeader);
  730. }
  731.  
  732. uint MemorySize(void *ptr)
  733. {
  734.     SUBALLOC_HEADER *header;
  735.  
  736.     if(ptr == NULL)
  737.     {
  738.         return 0;
  739.     }
  740.  
  741.     header = PointerToHeader(ptr);
  742.     assert(IsHeaderOkay(header) == TRUE);
  743.  
  744.     if(IsHeaderOkay(header) == FALSE)
  745.     {
  746.         return 0;
  747.     }
  748.  
  749.     return header->userSize;
  750. }
  751.  
  752.